package com.leo.netty.chart;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.concurrent.GlobalEventExecutor;

/**
 * @author du
 */
public class ChartServer {

    private int port;

    public ChartServer(int port) {
        this.port = port;
    }

    public void run () throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //inbound
                            ch.pipeline().addLast("decoder", new StringDecoder());
                            //outbound
                            ch.pipeline().addLast("encoder", new StringEncoder());
                            // 自定义inbound
                            ch.pipeline().addLast("myServerHandler", new ServerHandler());
                            System.out.println("Channel 初始化完毕.");
                        }
                    });

            b.bind(port).sync().addListener((ChannelFutureListener) future -> {
                if (future.isSuccess()) {
                    System.out.println("监听端口8888成功");
                } else {
                    System.out.println("监听端口8888失败");
                }
            }).channel().closeFuture().sync(); //监听关闭

        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        new ChartServer(8888).run();
    }


    static class ServerHandler extends SimpleChannelInboundHandler<String> {

        // 维护一个全局的 channel 集合
        private static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

        // channel处于活动
        @Override
        public void channelActive(ChannelHandlerContext ctx) {
            System.out.println("3.channelActive");
            System.out.println(ctx.channel().remoteAddress() + " 上线了.\n");
        }

        //
        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            System.out.println("channelInactive");
            System.out.println(ctx.channel().remoteAddress() + " 离线了.\n");
        }

        @Override
        public void channelRegistered(ChannelHandlerContext ctx) {
            System.out.println("2.channelRegistered");
        }

        // 连接建立, 会触发
        @Override
        public void handlerAdded(ChannelHandlerContext ctx) {
            System.out.println("1.handlerAdded");
            channels.writeAndFlush("[客户端]" + ctx.channel().remoteAddress() + " 加入聊天室.\n");
            channels.add(ctx.channel());
        }

        // 断开连接时触发
        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
            //channels.remove(ctx.channel()); //内部会自行删除channel
            channels.writeAndFlush("[客户端]" + ctx.channel().remoteAddress() + " 离开聊天室.\n" );
        }

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
            Channel channel = ctx.channel();
            channels.forEach(ch -> {
                if (channel != ch) {
                    ch.writeAndFlush("[客户端]" + ch.remoteAddress() + " 说: " + msg + "\n");
                } else {
                    ch.writeAndFlush("[我说]: " + msg  + "\n");
                }
            });
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.close();
        }
    }
}
